home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / GLUT / progs / examples / glpuzzle.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  29KB  |  1,438 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <malloc.h>
  6. #include <time.h>
  7. #include <math.h>
  8. #include <GL/glut.h>
  9. #include "trackball.h"
  10.  
  11. #define WIDTH 4
  12. #define HEIGHT 5
  13. #define PIECES 10
  14. #define OFFSETX -2
  15. #define OFFSETY -2.5
  16. #define OFFSETZ -0.5
  17.  
  18. typedef char Config[HEIGHT][WIDTH];
  19.  
  20. struct puzzle {
  21.   struct puzzle *backptr;
  22.   struct puzzle *solnptr;
  23.   Config pieces;
  24.   struct puzzle *next;
  25.   unsigned hashvalue;
  26. };
  27.  
  28. #define HASHSIZE 10691
  29.  
  30. struct puzzlelist {
  31.   struct puzzle *puzzle;
  32.   struct puzzlelist *next;
  33. };
  34.  
  35. static char convert[PIECES + 1] =
  36. {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
  37.  
  38. static unsigned char colors[PIECES + 1][3] =
  39. {
  40.   {0, 0, 0},
  41.   {255, 255, 127},
  42.   {255, 255, 127},
  43.   {255, 255, 127},
  44.   {255, 255, 127},
  45.   {255, 127, 255},
  46.   {255, 127, 255},
  47.   {255, 127, 255},
  48.   {255, 127, 255},
  49.   {255, 127, 127},
  50.   {255, 255, 255},
  51. };
  52.  
  53. void changeState(void);
  54.  
  55. static struct puzzle *hashtable[HASHSIZE];
  56. static struct puzzle *startPuzzle;
  57. static struct puzzlelist *puzzles;
  58. static struct puzzlelist *lastentry;
  59.  
  60. int curX, curY, visible;
  61.  
  62. #define MOVE_SPEED 0.2
  63. static unsigned char movingPiece;
  64. static float move_x, move_y;
  65. static float curquat[4];
  66. static int doubleBuffer = 1;
  67. static int depth = 1;
  68.  
  69. static char xsize[PIECES + 1] =
  70. {0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2};
  71. static char ysize[PIECES + 1] =
  72. {0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2};
  73. static float zsize[PIECES + 1] =
  74. {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6};
  75.  
  76. static Config startConfig =
  77. {
  78.   {8, 10, 10, 7},
  79.   {8, 10, 10, 7},
  80.   {6, 9, 9, 5},
  81.   {6, 4, 3, 5},
  82.   {2, 0, 0, 1}
  83. };
  84.  
  85. static Config thePuzzle =
  86. {
  87.   {8, 10, 10, 7},
  88.   {8, 10, 10, 7},
  89.   {6, 9, 9, 5},
  90.   {6, 4, 3, 5},
  91.   {2, 0, 0, 1}
  92. };
  93.  
  94. static int xadds[4] =
  95. {-1, 0, 1, 0};
  96. static int yadds[4] =
  97. {0, -1, 0, 1};
  98.  
  99. static long W = 400, H = 300;
  100. static GLint viewport[4];
  101.  
  102. #define srandom srand
  103. #define random() (rand() >> 2)
  104.  
  105. unsigned
  106. hash(Config config)
  107. {
  108.   int i, j, value;
  109.  
  110.   value = 0;
  111.   for (i = 0; i < HEIGHT; i++) {
  112.     for (j = 0; j < WIDTH; j++) {
  113.       value = value + convert[config[i][j]];
  114.       value *= 6;
  115.     }
  116.   }
  117.   return (value);
  118. }
  119.  
  120. int
  121. solution(Config config)
  122. {
  123.   if (config[4][1] == 10 && config[4][2] == 10)
  124.     return (1);
  125.   return (0);
  126. }
  127.  
  128. float boxcoords[][3] =
  129. {
  130.   {0.2, 0.2, 0.9},
  131.   {0.8, 0.2, 0.9},
  132.   {0.8, 0.8, 0.9},
  133.   {0.2, 0.8, 0.9},
  134.   {0.2, 0.1, 0.8},
  135.   {0.8, 0.1, 0.8},
  136.   {0.9, 0.2, 0.8},
  137.   {0.9, 0.8, 0.8},
  138.   {0.8, 0.9, 0.8},
  139.   {0.2, 0.9, 0.8},
  140.   {0.1, 0.8, 0.8},
  141.   {0.1, 0.2, 0.8},
  142.   {0.2, 0.1, 0.2},
  143.   {0.8, 0.1, 0.2},
  144.   {0.9, 0.2, 0.2},
  145.   {0.9, 0.8, 0.2},
  146.   {0.8, 0.9, 0.2},
  147.   {0.2, 0.9, 0.2},
  148.   {0.1, 0.8, 0.2},
  149.   {0.1, 0.2, 0.2},
  150.   {0.2, 0.2, 0.1},
  151.   {0.8, 0.2, 0.1},
  152.   {0.8, 0.8, 0.1},
  153.   {0.2, 0.8, 0.1},
  154. };
  155.  
  156. float boxnormals[][3] =
  157. {
  158.   {0, 0, 1},            /* 0 */
  159.   {0, 1, 0},
  160.   {1, 0, 0},
  161.   {0, 0, -1},
  162.   {0, -1, 0},
  163.   {-1, 0, 0},
  164.   {0.7071, 0.7071, 0.0000},  /* 6 */
  165.   {0.7071, -0.7071, 0.0000},
  166.   {-0.7071, 0.7071, 0.0000},
  167.   {-0.7071, -0.7071, 0.0000},
  168.   {0.7071, 0.0000, 0.7071},  /* 10 */
  169.   {0.7071, 0.0000, -0.7071},
  170.   {-0.7071, 0.0000, 0.7071},
  171.   {-0.7071, 0.0000, -0.7071},
  172.   {0.0000, 0.7071, 0.7071},  /* 14 */
  173.   {0.0000, 0.7071, -0.7071},
  174.   {0.0000, -0.7071, 0.7071},
  175.   {0.0000, -0.7071, -0.7071},
  176.   {0.5774, 0.5774, 0.5774},  /* 18 */
  177.   {0.5774, 0.5774, -0.5774},
  178.   {0.5774, -0.5774, 0.5774},
  179.   {0.5774, -0.5774, -0.5774},
  180.   {-0.5774, 0.5774, 0.5774},
  181.   {-0.5774, 0.5774, -0.5774},
  182.   {-0.5774, -0.5774, 0.5774},
  183.   {-0.5774, -0.5774, -0.5774},
  184. };
  185.  
  186. int boxfaces[][4] =
  187. {
  188.   {0, 1, 2, 3},         /* 0 */
  189.   {9, 8, 16, 17},
  190.   {6, 14, 15, 7},
  191.   {20, 23, 22, 21},
  192.   {12, 13, 5, 4},
  193.   {19, 11, 10, 18},
  194.   {7, 15, 16, 8},       /* 6 */
  195.   {13, 14, 6, 5},
  196.   {18, 10, 9, 17},
  197.   {19, 12, 4, 11},
  198.   {1, 6, 7, 2},         /* 10 */
  199.   {14, 21, 22, 15},
  200.   {11, 0, 3, 10},
  201.   {20, 19, 18, 23},
  202.   {3, 2, 8, 9},         /* 14 */
  203.   {17, 16, 22, 23},
  204.   {4, 5, 1, 0},
  205.   {20, 21, 13, 12},
  206.   {2, 7, 8, -1},        /* 18 */
  207.   {16, 15, 22, -1},
  208.   {5, 6, 1, -1},
  209.   {13, 21, 14, -1},
  210.   {10, 3, 9, -1},
  211.   {18, 17, 23, -1},
  212.   {11, 4, 0, -1},
  213.   {20, 12, 19, -1},
  214. };
  215.  
  216. #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
  217.  
  218. /* Draw a box.  Bevel as desired. */
  219. void
  220. drawBox(int piece, float xoff, float yoff)
  221. {
  222.   int xlen, ylen;
  223.   int i, k;
  224.   float x, y, z;
  225.   float zlen;
  226.   float *v;
  227.  
  228.   xlen = xsize[piece];
  229.   ylen = ysize[piece];
  230.   zlen = zsize[piece];
  231.  
  232.   glColor3ubv(colors[piece]);
  233.   glBegin(GL_QUADS);
  234.   for (i = 0; i < 18; i++) {
  235.     glNormal3fv(boxnormals[i]);
  236.     for (k = 0; k < 4; k++) {
  237.       if (boxfaces[i][k] == -1)
  238.         continue;
  239.       v = boxcoords[boxfaces[i][k]];
  240.       x = v[0] + OFFSETX;
  241.       if (v[0] > 0.5)
  242.         x += xlen - 1;
  243.       y = v[1] + OFFSETY;
  244.       if (v[1] > 0.5)
  245.         y += ylen - 1;
  246.       z = v[2] + OFFSETZ;
  247.       if (v[2] > 0.5)
  248.         z += zlen - 1;
  249.       glVertex3f(xoff + x, yoff + y, z);
  250.     }
  251.   }
  252.   glEnd();
  253.   glBegin(GL_TRIANGLES);
  254.   for (i = 18; i < NBOXFACES; i++) {
  255.     glNormal3fv(boxnormals[i]);
  256.     for (k = 0; k < 3; k++) {
  257.       if (boxfaces[i][k] == -1)
  258.         continue;
  259.       v = boxcoords[boxfaces[i][k]];
  260.       x = v[0] + OFFSETX;
  261.       if (v[0] > 0.5)
  262.         x += xlen - 1;
  263.       y = v[1] + OFFSETY;
  264.       if (v[1] > 0.5)
  265.         y += ylen - 1;
  266.       z = v[2] + OFFSETZ;
  267.       if (v[2] > 0.5)
  268.         z += zlen - 1;
  269.       glVertex3f(xoff + x, yoff + y, z);
  270.     }
  271.   }
  272.   glEnd();
  273. }
  274.  
  275. float containercoords[][3] =
  276. {
  277.   {-0.1, -0.1, 1.0},
  278.   {-0.1, -0.1, -0.1},
  279.   {4.1, -0.1, -0.1},
  280.   {4.1, -0.1, 1.0},
  281.   {1.0, -0.1, 0.6},     /* 4 */
  282.   {3.0, -0.1, 0.6},
  283.   {1.0, -0.1, 0.0},
  284.   {3.0, -0.1, 0.0},
  285.   {1.0, 0.0, 0.0},      /* 8 */
  286.   {3.0, 0.0, 0.0},
  287.   {3.0, 0.0, 0.6},
  288.   {1.0, 0.0, 0.6},
  289.   {0.0, 0.0, 1.0},      /* 12 */
  290.   {4.0, 0.0, 1.0},
  291.   {4.0, 0.0, 0.0},
  292.   {0.0, 0.0, 0.0},
  293.   {0.0, 5.0, 0.0},      /* 16 */
  294.   {0.0, 5.0, 1.0},
  295.   {4.0, 5.0, 1.0},
  296.   {4.0, 5.0, 0.0},
  297.   {-0.1, 5.1, -0.1},    /* 20 */
  298.   {4.1, 5.1, -0.1},
  299.   {4.1, 5.1, 1.0},
  300.   {-0.1, 5.1, 1.0},
  301. };
  302.  
  303. float containernormals[][3] =
  304. {
  305.   {0, -1, 0},
  306.   {0, -1, 0},
  307.   {0, -1, 0},
  308.   {0, -1, 0},
  309.   {0, -1, 0},
  310.   {0, 1, 0},
  311.   {0, 1, 0},
  312.   {0, 1, 0},
  313.   {1, 0, 0},
  314.   {1, 0, 0},
  315.   {1, 0, 0},
  316.   {-1, 0, 0},
  317.   {-1, 0, 0},
  318.   {-1, 0, 0},
  319.   {0, 1, 0},
  320.   {0, 0, -1},
  321.   {0, 0, -1},
  322.   {0, 0, 1},
  323.   {0, 0, 1},
  324.   {0, 0, 1},
  325.   {0, 0, 1},
  326.   {0, 0, 1},
  327.   {0, 0, 1},
  328.   {0, 0, 1},
  329. };
  330.  
  331. int containerfaces[][4] =
  332. {
  333.   {1, 6, 4, 0},
  334.   {0, 4, 5, 3},
  335.   {1, 2, 7, 6},
  336.   {7, 2, 3, 5},
  337.   {16, 19, 18, 17},
  338.  
  339.   {23, 22, 21, 20},
  340.   {12, 11, 8, 15},
  341.   {10, 13, 14, 9},
  342.  
  343.   {15, 16, 17, 12},
  344.   {2, 21, 22, 3},
  345.   {6, 8, 11, 4},
  346.  
  347.   {1, 0, 23, 20},
  348.   {14, 13, 18, 19},
  349.   {9, 7, 5, 10},
  350.  
  351.   {12, 13, 10, 11},
  352.  
  353.   {1, 20, 21, 2},
  354.   {4, 11, 10, 5},
  355.  
  356.   {15, 8, 19, 16},
  357.   {19, 8, 9, 14},
  358.   {8, 6, 7, 9},
  359.   {0, 3, 13, 12},
  360.   {13, 3, 22, 18},
  361.   {18, 22, 23, 17},
  362.   {17, 23, 0, 12},
  363. };
  364.  
  365. #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
  366.  
  367. /* Draw the container */
  368. void
  369. drawContainer(void)
  370. {
  371.   int i, k;
  372.   float *v;
  373.  
  374.   /* Y is reversed here because the model has it reversed */
  375.  
  376.   /* Arbitrary bright wood-like color */
  377.   glColor3ub(209, 103, 23);
  378.   glBegin(GL_QUADS);
  379.   for (i = 0; i < NCONTFACES; i++) {
  380.     v = containernormals[i];
  381.     glNormal3f(v[0], -v[1], v[2]);
  382.     for (k = 3; k >= 0; k--) {
  383.       v = containercoords[containerfaces[i][k]];
  384.       glVertex3f(v[0] + OFFSETX, -(v[1] + OFFSETY), v[2] + OFFSETZ);
  385.     }
  386.   }
  387.   glEnd();
  388. }
  389.  
  390. void
  391. drawAll(void)
  392. {
  393.   int i, j;
  394.   int piece;
  395.   char done[PIECES + 1];
  396.   float m[4][4];
  397.  
  398.   build_rotmatrix(m, curquat);
  399.   glMatrixMode(GL_MODELVIEW);
  400.   glLoadIdentity();
  401.   glTranslatef(0, 0, -10);
  402.   glMultMatrixf(&(m[0][0]));
  403.   glRotatef(180, 0, 0, 1);
  404.  
  405.   if (depth) {
  406.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  407.   } else {
  408.     glClear(GL_COLOR_BUFFER_BIT);
  409.   }
  410.   for (i = 1; i <= PIECES; i++) {
  411.     done[i] = 0;
  412.   }
  413.   glLoadName(0);
  414.   drawContainer();
  415.   for (i = 0; i < HEIGHT; i++) {
  416.     for (j = 0; j < WIDTH; j++) {
  417.       piece = thePuzzle[i][j];
  418.       if (piece == 0)
  419.         continue;
  420.       if (done[piece])
  421.         continue;
  422.       done[piece] = 1;
  423.       glLoadName(piece);
  424.       if (piece == movingPiece) {
  425.         drawBox(piece, move_x, move_y);
  426.       } else {
  427.         drawBox(piece, j, i);
  428.       }
  429.     }
  430.   }
  431. }
  432.  
  433. void
  434. redraw(void)
  435. {
  436.   glMatrixMode(GL_PROJECTION);
  437.   glLoadIdentity();
  438.   gluPerspective(45, 1.0, 0.1, 100.0);
  439.  
  440.   drawAll();
  441.  
  442.   if (doubleBuffer)
  443.     glutSwapBuffers();
  444.   else
  445.     glFinish();
  446. }
  447.  
  448. void
  449. solidifyChain(struct puzzle *puzzle)
  450. {
  451.   int i;
  452.   char buf[256];
  453.  
  454.   i = 0;
  455.   while (puzzle->backptr) {
  456.     i++;
  457.     puzzle->backptr->solnptr = puzzle;
  458.     puzzle = puzzle->backptr;
  459.   }
  460.   sprintf(buf, "%d moves to complete!", i);
  461.   glutSetWindowTitle(buf);
  462. }
  463.  
  464. int
  465. addConfig(Config config, struct puzzle *back)
  466. {
  467.   unsigned hashvalue;
  468.   struct puzzle *newpiece;
  469.   struct puzzlelist *newlistentry;
  470.  
  471.   hashvalue = hash(config);
  472.  
  473.   newpiece = hashtable[hashvalue % HASHSIZE];
  474.   while (newpiece != NULL) {
  475.     if (newpiece->hashvalue == hashvalue) {
  476.       int i, j;
  477.  
  478.       for (i = 0; i < WIDTH; i++) {
  479.         for (j = 0; j < HEIGHT; j++) {
  480.           if (convert[config[j][i]] !=
  481.             convert[newpiece->pieces[j][i]])
  482.             goto nomatch;
  483.         }
  484.       }
  485.       return 0;
  486.     }
  487.   nomatch:
  488.     newpiece = newpiece->next;
  489.   }
  490.  
  491.   newpiece = (struct puzzle *) malloc(sizeof(struct puzzle));
  492.   newpiece->next = hashtable[hashvalue % HASHSIZE];
  493.   newpiece->hashvalue = hashvalue;
  494.   memcpy(newpiece->pieces, config, HEIGHT * WIDTH);
  495.   newpiece->backptr = back;
  496.   newpiece->solnptr = NULL;
  497.   hashtable[hashvalue % HASHSIZE] = newpiece;
  498.  
  499.   newlistentry = (struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  500.   newlistentry->puzzle = newpiece;
  501.   newlistentry->next = NULL;
  502.  
  503.   if (lastentry) {
  504.     lastentry->next = newlistentry;
  505.   } else {
  506.     puzzles = newlistentry;
  507.   }
  508.   lastentry = newlistentry;
  509.  
  510.   if (back == NULL) {
  511.     startPuzzle = newpiece;
  512.   }
  513.   if (solution(config)) {
  514.     solidifyChain(newpiece);
  515.     return 1;
  516.   }
  517.   return 0;
  518. }
  519.  
  520. /* Checks if a space can move */
  521. int
  522. canmove0(Config pieces, int x, int y, int dir, Config newpieces)
  523. {
  524.   char piece;
  525.   int xadd, yadd;
  526.   int l, m;
  527.  
  528.   xadd = xadds[dir];
  529.   yadd = yadds[dir];
  530.  
  531.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  532.     y + yadd < 0 || y + yadd >= HEIGHT)
  533.     return 0;
  534.   piece = pieces[y + yadd][x + xadd];
  535.   if (piece == 0)
  536.     return 0;
  537.   memcpy(newpieces, pieces, HEIGHT * WIDTH);
  538.   for (l = 0; l < WIDTH; l++) {
  539.     for (m = 0; m < HEIGHT; m++) {
  540.       if (newpieces[m][l] == piece)
  541.         newpieces[m][l] = 0;
  542.     }
  543.   }
  544.   xadd = -xadd;
  545.   yadd = -yadd;
  546.   for (l = 0; l < WIDTH; l++) {
  547.     for (m = 0; m < HEIGHT; m++) {
  548.       if (pieces[m][l] == piece) {
  549.         int newx, newy;
  550.  
  551.         newx = l + xadd;
  552.         newy = m + yadd;
  553.         if (newx < 0 || newx >= WIDTH ||
  554.           newy < 0 || newy >= HEIGHT)
  555.           return 0;
  556.         if (newpieces[newy][newx] != 0)
  557.           return 0;
  558.         newpieces[newy][newx] = piece;
  559.       }
  560.     }
  561.   }
  562.   return 1;
  563. }
  564.  
  565. /* Checks if a piece can move */
  566. int
  567. canmove(Config pieces, int x, int y, int dir, Config newpieces)
  568. {
  569.   int xadd, yadd;
  570.  
  571.   xadd = xadds[dir];
  572.   yadd = yadds[dir];
  573.  
  574.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  575.     y + yadd < 0 || y + yadd >= HEIGHT)
  576.     return 0;
  577.   if (pieces[y + yadd][x + xadd] == pieces[y][x]) {
  578.     return canmove(pieces, x + xadd, y + yadd, dir, newpieces);
  579.   }
  580.   if (pieces[y + yadd][x + xadd] != 0)
  581.     return 0;
  582.   return canmove0(pieces, x + xadd, y + yadd, (dir + 2) % 4, newpieces);
  583. }
  584.  
  585. int
  586. generateNewConfigs(struct puzzle *puzzle)
  587. {
  588.   int i, j, k;
  589.   Config pieces;
  590.   Config newpieces;
  591.  
  592.   memcpy(pieces, puzzle->pieces, HEIGHT * WIDTH);
  593.   for (i = 0; i < WIDTH; i++) {
  594.     for (j = 0; j < HEIGHT; j++) {
  595.       if (pieces[j][i] == 0) {
  596.         for (k = 0; k < 4; k++) {
  597.           if (canmove0(pieces, i, j, k, newpieces)) {
  598.             if (addConfig(newpieces, puzzle))
  599.               return 1;
  600.           }
  601.         }
  602.       }
  603.     }
  604.   }
  605.   return 0;
  606. }
  607.  
  608. void
  609. freeSolutions(void)
  610. {
  611.   struct puzzlelist *nextpuz;
  612.   struct puzzle *puzzle, *next;
  613.   int i;
  614.  
  615.   while (puzzles) {
  616.     nextpuz = puzzles->next;
  617.     free((char *) puzzles);
  618.     puzzles = nextpuz;
  619.   }
  620.   lastentry = NULL;
  621.   for (i = 0; i < HASHSIZE; i++) {
  622.     puzzle = hashtable[i];
  623.     hashtable[i] = NULL;
  624.     while (puzzle) {
  625.       next = puzzle->next;
  626.       free((char *) puzzle);
  627.       puzzle = next;
  628.     }
  629.   }
  630.   startPuzzle = NULL;
  631. }
  632.  
  633. int
  634. continueSolving(void)
  635. {
  636.   struct puzzle *nextpuz;
  637.   int i, j;
  638.   int movedPiece;
  639.   int movedir;
  640.   int fromx, fromy;
  641.   int tox, toy;
  642.  
  643.   if (startPuzzle == NULL)
  644.     return 0;
  645.   if (startPuzzle->solnptr == NULL) {
  646.     freeSolutions();
  647.     return 0;
  648.   }
  649.   nextpuz = startPuzzle->solnptr;
  650.   movedPiece = 0;
  651.   movedir = 0;
  652.   for (i = 0; i < HEIGHT; i++) {
  653.     for (j = 0; j < WIDTH; j++) {
  654.       if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
  655.         if (startPuzzle->pieces[i][j]) {
  656.           movedPiece = startPuzzle->pieces[i][j];
  657.           fromx = j;
  658.           fromy = i;
  659.           if (i < HEIGHT - 1 && nextpuz->pieces[i + 1][j] == movedPiece) {
  660.             movedir = 3;
  661.           } else {
  662.             movedir = 2;
  663.           }
  664.           goto found_piece;
  665.         } else {
  666.           movedPiece = nextpuz->pieces[i][j];
  667.           if (i < HEIGHT - 1 &&
  668.             startPuzzle->pieces[i + 1][j] == movedPiece) {
  669.             fromx = j;
  670.             fromy = i + 1;
  671.             movedir = 1;
  672.           } else {
  673.             fromx = j + 1;
  674.             fromy = i;
  675.             movedir = 0;
  676.           }
  677.           goto found_piece;
  678.         }
  679.       }
  680.     }
  681.   }
  682.   glutSetWindowTitle("What!  No change?");
  683.   freeSolutions();
  684.   return 0;
  685.  
  686. found_piece:
  687.   if (!movingPiece) {
  688.     movingPiece = movedPiece;
  689.     move_x = fromx;
  690.     move_y = fromy;
  691.   }
  692.   move_x += xadds[movedir] * MOVE_SPEED;
  693.   move_y += yadds[movedir] * MOVE_SPEED;
  694.  
  695.   tox = fromx + xadds[movedir];
  696.   toy = fromy + yadds[movedir];
  697.  
  698.   if (move_x > tox - MOVE_SPEED / 2 && move_x < tox + MOVE_SPEED / 2 &&
  699.     move_y > toy - MOVE_SPEED / 2 && move_y < toy + MOVE_SPEED / 2) {
  700.     startPuzzle = nextpuz;
  701.     movingPiece = 0;
  702.   }
  703.   memcpy(thePuzzle, startPuzzle->pieces, HEIGHT * WIDTH);
  704.   changeState();
  705.   return 1;
  706. }
  707.  
  708. int
  709. solvePuzzle(void)
  710. {
  711.   struct puzzlelist *nextpuz;
  712.   char buf[256];
  713.   int i;
  714.  
  715.   if (solution(thePuzzle)) {
  716.     glutSetWindowTitle("Puzzle already solved!");
  717.     return 0;
  718.   }
  719.   addConfig(thePuzzle, NULL);
  720.   i = 0;
  721.  
  722.   while (puzzles) {
  723.     i++;
  724.     if (generateNewConfigs(puzzles->puzzle))
  725.       break;
  726.     nextpuz = puzzles->next;
  727.     free((char *) puzzles);
  728.     puzzles = nextpuz;
  729.   }
  730.   if (puzzles == NULL) {
  731.     freeSolutions();
  732.     sprintf(buf, "I can't solve it! (%d positions examined)", i);
  733.     glutSetWindowTitle(buf);
  734.     return 1;
  735.   }
  736.   return 1;
  737. }
  738.  
  739. int
  740. selectPiece(int mousex, int mousey)
  741. {
  742.   long hits;
  743.   GLuint selectBuf[1024];
  744.   GLuint closest;
  745.   GLuint dist;
  746.  
  747.   glSelectBuffer(1024, selectBuf);
  748.   (void) glRenderMode(GL_SELECT);
  749.   glInitNames();
  750.  
  751.   /* Because LoadName() won't work with no names on the stack */
  752.   glPushName(-1);
  753.  
  754.   glMatrixMode(GL_PROJECTION);
  755.   glLoadIdentity();
  756.   gluPickMatrix(mousex, H - mousey, 4, 4, viewport);
  757.   gluPerspective(45, 1.0, 0.1, 100.0);
  758.  
  759.   drawAll();
  760.  
  761.   hits = glRenderMode(GL_RENDER);
  762.   if (hits <= 0) {
  763.     return 0;
  764.   }
  765.   closest = 0;
  766.   dist = 4294967295;
  767.   while (hits) {
  768.     if (selectBuf[(hits - 1) * 4 + 1] < dist) {
  769.       dist = selectBuf[(hits - 1) * 4 + 1];
  770.       closest = selectBuf[(hits - 1) * 4 + 3];
  771.     }
  772.     hits--;
  773.   }
  774.   return closest;
  775. }
  776.  
  777. void
  778. nukePiece(int piece)
  779. {
  780.   int i, j;
  781.  
  782.   for (i = 0; i < HEIGHT; i++) {
  783.     for (j = 0; j < WIDTH; j++) {
  784.       if (thePuzzle[i][j] == piece) {
  785.         thePuzzle[i][j] = 0;
  786.       }
  787.     }
  788.   }
  789. }
  790.  
  791. void
  792. multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
  793. {
  794.   int i, j;
  795.  
  796.   for (i = 0; i < 4; i++) {
  797.     for (j = 0; j < 4; j++) {
  798.       r[i * 4 + j] =
  799.         a[i * 4 + 0] * b[0 * 4 + j] +
  800.         a[i * 4 + 1] * b[1 * 4 + j] +
  801.         a[i * 4 + 2] * b[2 * 4 + j] +
  802.         a[i * 4 + 3] * b[3 * 4 + j];
  803.     }
  804.   }
  805. }
  806.  
  807. void
  808. makeIdentity(GLfloat m[16])
  809. {
  810.   m[0 + 4 * 0] = 1;
  811.   m[0 + 4 * 1] = 0;
  812.   m[0 + 4 * 2] = 0;
  813.   m[0 + 4 * 3] = 0;
  814.   m[1 + 4 * 0] = 0;
  815.   m[1 + 4 * 1] = 1;
  816.   m[1 + 4 * 2] = 0;
  817.   m[1 + 4 * 3] = 0;
  818.   m[2 + 4 * 0] = 0;
  819.   m[2 + 4 * 1] = 0;
  820.   m[2 + 4 * 2] = 1;
  821.   m[2 + 4 * 3] = 0;
  822.   m[3 + 4 * 0] = 0;
  823.   m[3 + 4 * 1] = 0;
  824.   m[3 + 4 * 2] = 0;
  825.   m[3 + 4 * 3] = 1;
  826. }
  827.  
  828. /*
  829.    ** inverse = invert(src)
  830.  */
  831. int
  832. invertMatrix(const GLfloat src[16], GLfloat inverse[16])
  833. {
  834.   int i, j, k, swap;
  835.   double t;
  836.   GLfloat temp[4][4];
  837.  
  838.   for (i = 0; i < 4; i++) {
  839.     for (j = 0; j < 4; j++) {
  840.       temp[i][j] = src[i * 4 + j];
  841.     }
  842.   }
  843.   makeIdentity(inverse);
  844.  
  845.   for (i = 0; i < 4; i++) {
  846.     /* 
  847.        ** Look for largest element in column */
  848.     swap = i;
  849.     for (j = i + 1; j < 4; j++) {
  850.       if (fabs(temp[j][i]) > fabs(temp[i][i])) {
  851.         swap = j;
  852.       }
  853.     }
  854.  
  855.     if (swap != i) {
  856.       /* 
  857.          ** Swap rows. */
  858.       for (k = 0; k < 4; k++) {
  859.         t = temp[i][k];
  860.         temp[i][k] = temp[swap][k];
  861.         temp[swap][k] = t;
  862.  
  863.         t = inverse[i * 4 + k];
  864.         inverse[i * 4 + k] = inverse[swap * 4 + k];
  865.         inverse[swap * 4 + k] = t;
  866.       }
  867.     }
  868.     if (temp[i][i] == 0) {
  869.       /* 
  870.          ** No non-zero pivot.  The matrix is singular, which
  871.          shouldn't ** happen.  This means the user gave us a
  872.          bad matrix. */
  873.       return 0;
  874.     }
  875.     t = temp[i][i];
  876.     for (k = 0; k < 4; k++) {
  877.       temp[i][k] /= t;
  878.       inverse[i * 4 + k] /= t;
  879.     }
  880.     for (j = 0; j < 4; j++) {
  881.       if (j != i) {
  882.         t = temp[j][i];
  883.         for (k = 0; k < 4; k++) {
  884.           temp[j][k] -= temp[i][k] * t;
  885.           inverse[j * 4 + k] -= inverse[i * 4 + k] * t;
  886.         }
  887.       }
  888.     }
  889.   }
  890.   return 1;
  891. }
  892.  
  893. /*
  894.    ** This is a screwball function.  What it does is the following:
  895.    ** Given screen x and y coordinates, compute the corresponding object space 
  896.    **   x and y coordinates given that the object space z is 0.9 + OFFSETZ.
  897.    ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that 
  898.    **   number.
  899.  */
  900. int
  901. computeCoords(int piece, int mousex, int mousey,
  902.   GLfloat * selx, GLfloat * sely)
  903. {
  904.   GLfloat modelMatrix[16];
  905.   GLfloat projMatrix[16];
  906.   GLfloat finalMatrix[16];
  907.   GLfloat in[4];
  908.   GLfloat a, b, c, d;
  909.   GLfloat top, bot;
  910.   GLfloat z;
  911.   GLfloat w;
  912.   GLfloat height;
  913.  
  914.   if (piece == 0)
  915.     return 0;
  916.   height = zsize[piece] - 0.1 + OFFSETZ;
  917.  
  918.   glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
  919.   glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
  920.   multMatrices(modelMatrix, projMatrix, finalMatrix);
  921.   if (!invertMatrix(finalMatrix, finalMatrix))
  922.     return 0;
  923.  
  924.   in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
  925.   in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
  926.  
  927.   a = in[0] * finalMatrix[0 * 4 + 2] +
  928.     in[1] * finalMatrix[1 * 4 + 2] +
  929.     finalMatrix[3 * 4 + 2];
  930.   b = finalMatrix[2 * 4 + 2];
  931.   c = in[0] * finalMatrix[0 * 4 + 3] +
  932.     in[1] * finalMatrix[1 * 4 + 3] +
  933.     finalMatrix[3 * 4 + 3];
  934.   d = finalMatrix[2 * 4 + 3];
  935.  
  936.   /* 
  937.      ** Ok, now we need to solve for z: **   (a + b z) / (c + d 
  938.  
  939.      z) = height. ** ("height" is the height in object space we 
  940.  
  941.      want to solve z for) ** ** ==>  a + b z = height c +
  942.      height d z **      bz - height d z = height c - a ** z =
  943.      (height c - a) / (b - height d) */
  944.   top = height * c - a;
  945.   bot = b - height * d;
  946.   if (bot == 0.0)
  947.     return 0;
  948.  
  949.   z = top / bot;
  950.  
  951.   /* 
  952.      ** Ok, no problem. ** Now we solve for x and y.  We know
  953.      that w = c + d z, so we compute it. */
  954.   w = c + d * z;
  955.  
  956.   /* 
  957.      ** Now for x and y: */
  958.   *selx = (in[0] * finalMatrix[0 * 4 + 0] +
  959.     in[1] * finalMatrix[1 * 4 + 0] +
  960.     z * finalMatrix[2 * 4 + 0] +
  961.     finalMatrix[3 * 4 + 0]) / w - OFFSETX;
  962.   *sely = (in[0] * finalMatrix[0 * 4 + 1] +
  963.     in[1] * finalMatrix[1 * 4 + 1] +
  964.     z * finalMatrix[2 * 4 + 1] +
  965.     finalMatrix[3 * 4 + 1]) / w - OFFSETY;
  966.   return 1;
  967. }
  968.  
  969. static int selected;
  970. static int selectx, selecty;
  971. static float selstartx, selstarty;
  972.  
  973. void
  974. grabPiece(int piece, float selx, float sely)
  975. {
  976.   int hit;
  977.  
  978.   selectx = selx;
  979.   selecty = sely;
  980.   if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
  981.     return;
  982.   }
  983.   hit = thePuzzle[selecty][selectx];
  984.   if (hit != piece)
  985.     return;
  986.   if (hit) {
  987.     movingPiece = hit;
  988.     while (selectx > 0 && thePuzzle[selecty][selectx - 1] == movingPiece) {
  989.       selectx--;
  990.     }
  991.     while (selecty > 0 && thePuzzle[selecty - 1][selectx] == movingPiece) {
  992.       selecty--;
  993.     }
  994.     move_x = selectx;
  995.     move_y = selecty;
  996.     selected = 1;
  997.     selstartx = selx;
  998.     selstarty = sely;
  999.   } else {
  1000.     selected = 0;
  1001.   }
  1002.   changeState();
  1003. }
  1004.  
  1005. void
  1006. moveSelection(float selx, float sely)
  1007. {
  1008.   float deltax, deltay;
  1009.   int dir;
  1010.   Config newpieces;
  1011.  
  1012.   if (!selected)
  1013.     return;
  1014.   deltax = selx - selstartx;
  1015.   deltay = sely - selstarty;
  1016.  
  1017.   if (fabs(deltax) > fabs(deltay)) {
  1018.     deltay = 0;
  1019.     if (deltax > 0) {
  1020.       if (deltax > 1)
  1021.         deltax = 1;
  1022.       dir = 2;
  1023.     } else {
  1024.       if (deltax < -1)
  1025.         deltax = -1;
  1026.       dir = 0;
  1027.     }
  1028.   } else {
  1029.     deltax = 0;
  1030.     if (deltay > 0) {
  1031.       if (deltay > 1)
  1032.         deltay = 1;
  1033.       dir = 3;
  1034.     } else {
  1035.       if (deltay < -1)
  1036.         deltay = -1;
  1037.       dir = 1;
  1038.     }
  1039.   }
  1040.   if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
  1041.     move_x = deltax + selectx;
  1042.     move_y = deltay + selecty;
  1043.     if (deltax > 0.5) {
  1044.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1045.       selectx++;
  1046.       selstartx++;
  1047.     } else if (deltax < -0.5) {
  1048.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1049.       selectx--;
  1050.       selstartx--;
  1051.     } else if (deltay > 0.5) {
  1052.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1053.       selecty++;
  1054.       selstarty++;
  1055.     } else if (deltay < -0.5) {
  1056.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1057.       selecty--;
  1058.       selstarty--;
  1059.     }
  1060.   } else {
  1061.     if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
  1062.       selectx == 1 && selecty == 3) {
  1063.       /* Allow visual movement of solution piece outside of the 
  1064.  
  1065.          box */
  1066.       move_x = selectx;
  1067.       move_y = sely - selstarty + selecty;
  1068.     } else {
  1069.       move_x = selectx;
  1070.       move_y = selecty;
  1071.     }
  1072.   }
  1073. }
  1074.  
  1075. void
  1076. dropSelection(void)
  1077. {
  1078.   if (!selected)
  1079.     return;
  1080.   movingPiece = 0;
  1081.   selected = 0;
  1082.   changeState();
  1083. }
  1084.  
  1085. static int left_mouse, middle_mouse;
  1086. static int mousex, mousey;
  1087. static int solving;
  1088. static int spinning;
  1089. static float lastquat[4];
  1090. static int sel_piece;
  1091.  
  1092. static void
  1093. Reshape(int width, int height)
  1094. {
  1095.  
  1096.   W = width;
  1097.   H = height;
  1098.   glViewport(0, 0, W, H);
  1099.   glGetIntegerv(GL_VIEWPORT, viewport);
  1100. }
  1101.  
  1102. void
  1103. toggleSolve(void)
  1104. {
  1105.     if (solving) {
  1106.       freeSolutions();
  1107.       solving = 0;
  1108.       glutChangeToMenuEntry(1, "Solving", 1);
  1109.       glutSetWindowTitle("glpuzzle");
  1110.       movingPiece = 0;
  1111.     } else {
  1112.       glutChangeToMenuEntry(1, "Stop solving", 1);
  1113.       glutSetWindowTitle("Solving...");
  1114.       if (solvePuzzle()) {
  1115.         solving = 1;
  1116.       }
  1117.     }
  1118.     changeState();
  1119.     glutPostRedisplay();
  1120. }
  1121.  
  1122. void reset(void)
  1123. {
  1124.     if (solving) {
  1125.       freeSolutions();
  1126.       solving = 0;
  1127.       glutChangeToMenuEntry(1, "Solving", 1);
  1128.       glutSetWindowTitle("glpuzzle");
  1129.       movingPiece = 0;
  1130.       changeState();
  1131.     }
  1132.     memcpy(thePuzzle, startConfig, HEIGHT * WIDTH);
  1133.     glutPostRedisplay();
  1134. }
  1135.  
  1136. void
  1137. keyboard(unsigned char c, int x, int y)
  1138. {
  1139.   int piece;
  1140.  
  1141.   switch (c) {
  1142.   case 27:
  1143.     exit(0);
  1144.     break;
  1145.   case 'D':
  1146.   case 'd':
  1147.     if (solving) {
  1148.       freeSolutions();
  1149.       solving = 0;
  1150.       glutChangeToMenuEntry(1, "Solving", 1);
  1151.       glutSetWindowTitle("glpuzzle");
  1152.       movingPiece = 0;
  1153.       changeState();
  1154.     }
  1155.     piece = selectPiece(x, y);
  1156.     if (piece) {
  1157.       nukePiece(piece);
  1158.     }
  1159.     glutPostRedisplay();
  1160.     break;
  1161.   case 'R':
  1162.   case 'r':
  1163.     reset();
  1164.     break;
  1165.   case 'S':
  1166.   case 's':
  1167.     toggleSolve();
  1168.     break;
  1169.   case 'b':
  1170.   case 'B':
  1171.     depth = 1 - depth;
  1172.     if (depth) {
  1173.       glEnable(GL_DEPTH_TEST);
  1174.     } else {
  1175.       glDisable(GL_DEPTH_TEST);
  1176.     }
  1177.     glutPostRedisplay();
  1178.     break;
  1179.   default:
  1180.     break;
  1181.   }
  1182. }
  1183.  
  1184. void
  1185. motion(int x, int y)
  1186. {
  1187.   float selx, sely;
  1188.  
  1189.   if (middle_mouse && !left_mouse) {
  1190.     if (mousex != x || mousey != y) {
  1191.       trackball(lastquat,
  1192.         (2.0*mousex - W) / W,
  1193.         (H - 2.0*mousey) / H,
  1194.         (2.0*x - W) / W,
  1195.         (H - 2.0*y) / H);
  1196.       spinning = 1;
  1197.     } else {
  1198.       spinning = 0;
  1199.     }
  1200.     changeState();
  1201.   } else {
  1202.     computeCoords(sel_piece, x, y, &selx, &sely);
  1203.     moveSelection(selx, sely);
  1204.   }
  1205.   mousex = x;
  1206.   mousey = y;
  1207.   glutPostRedisplay();
  1208. }
  1209.  
  1210. void
  1211. mouse(int b, int s, int x, int y)
  1212. {
  1213.   float selx, sely;
  1214.  
  1215.   mousex = x;
  1216.   mousey = y;
  1217.   curX = x;
  1218.   curY = y;
  1219.   if (s == GLUT_DOWN) {
  1220.     switch (b) {
  1221.     case GLUT_LEFT_BUTTON:
  1222.       if (solving) {
  1223.         freeSolutions();
  1224.         solving = 0;
  1225.       glutChangeToMenuEntry(1, "Solving", 1);
  1226.         glutSetWindowTitle("glpuzzle");
  1227.         movingPiece = 0;
  1228.       }
  1229.       left_mouse = GL_TRUE;
  1230.       sel_piece = selectPiece(mousex, mousey);
  1231.       if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
  1232.         grabPiece(sel_piece, selx, sely);
  1233.       }
  1234.       glutPostRedisplay();
  1235.       break;
  1236.     case GLUT_MIDDLE_BUTTON:
  1237.       middle_mouse = GL_TRUE;
  1238.       glutPostRedisplay();
  1239.       break;
  1240.     }
  1241.   } else {
  1242.     switch (b) {
  1243.     case GLUT_LEFT_BUTTON:
  1244.       left_mouse = GL_FALSE;
  1245.       dropSelection();
  1246.       glutPostRedisplay();
  1247.       break;
  1248.     case GLUT_MIDDLE_BUTTON:
  1249.       middle_mouse = GL_FALSE;
  1250.       glutPostRedisplay();
  1251.       break;
  1252.     }
  1253.   }
  1254.   motion(x, y);
  1255. }
  1256.  
  1257. void
  1258. animate(void)
  1259. {
  1260.   if (spinning) {
  1261.     add_quats(lastquat, curquat, curquat);
  1262.   }
  1263.   glutPostRedisplay();
  1264.   if (solving) {
  1265.     if (!continueSolving()) {
  1266.       solving = 0;
  1267.       glutChangeToMenuEntry(1, "Solving", 1);
  1268.       glutSetWindowTitle("glpuzzle");
  1269.     }
  1270.   }
  1271.   if (!solving && !spinning && !visible) {
  1272.     glutIdleFunc(NULL);
  1273.   }
  1274. }
  1275.  
  1276. void
  1277. changeState(void)
  1278. {
  1279.   if (visible) {
  1280.     if (!solving && !spinning) {
  1281.       glutIdleFunc(NULL);
  1282.     } else {
  1283.       glutIdleFunc(animate);
  1284.     }
  1285.   } else {
  1286.     glutIdleFunc(NULL);
  1287.   }
  1288. }
  1289.  
  1290. void
  1291. init(void)
  1292. {
  1293.   static float lmodel_ambient[] =
  1294.   {0.0, 0.0, 0.0, 0.0};
  1295.   static float lmodel_twoside[] =
  1296.   {GL_FALSE};
  1297.   static float lmodel_local[] =
  1298.   {GL_FALSE};
  1299.   static float light0_ambient[] =
  1300.   {0.1, 0.1, 0.1, 1.0};
  1301.   static float light0_diffuse[] =
  1302.   {1.0, 1.0, 1.0, 0.0};
  1303.   static float light0_position[] =
  1304.   {0.8660254, 0.5, 1, 0};
  1305.   static float light0_specular[] =
  1306.   {0.0, 0.0, 0.0, 0.0};
  1307.   static float bevel_mat_ambient[] =
  1308.   {0.0, 0.0, 0.0, 1.0};
  1309.   static float bevel_mat_shininess[] =
  1310.   {40.0};
  1311.   static float bevel_mat_specular[] =
  1312.   {0.0, 0.0, 0.0, 0.0};
  1313.   static float bevel_mat_diffuse[] =
  1314.   {1.0, 0.0, 0.0, 0.0};
  1315.  
  1316.   glEnable(GL_CULL_FACE);
  1317.   glCullFace(GL_BACK);
  1318.   glEnable(GL_DEPTH_TEST);
  1319.   glClearDepth(1.0);
  1320.  
  1321.   glClearColor(0.5, 0.5, 0.5, 0.0);
  1322.   glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  1323.   glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  1324.   glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
  1325.   glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  1326.   glEnable(GL_LIGHT0);
  1327.  
  1328.   glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
  1329.   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
  1330.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  1331.   glEnable(GL_LIGHTING);
  1332.  
  1333.   glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
  1334.   glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
  1335.   glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
  1336.   glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
  1337.  
  1338.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  1339.   glEnable(GL_COLOR_MATERIAL);
  1340.   glShadeModel(GL_FLAT);
  1341.  
  1342.   trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  1343.   srandom(time(NULL));
  1344. }
  1345.  
  1346. static void
  1347. Usage(void)
  1348. {
  1349.   printf("Usage: puzzle [-s]\n");
  1350.   printf("   -s:  Run in single buffered mode\n");
  1351.   exit(-1);
  1352. }
  1353.  
  1354. void
  1355. visibility(int v)
  1356. {
  1357.   if (v == GLUT_VISIBLE) {
  1358.     visible = 1;
  1359.   } else {
  1360.     visible = 0;
  1361.   }
  1362.   changeState();
  1363. }
  1364.  
  1365. void
  1366. menu(int choice)
  1367. {
  1368.    switch(choice) {
  1369.    case 1:
  1370.       toggleSolve();
  1371.       break;
  1372.    case 2:
  1373.       reset();
  1374.       break;
  1375.    case 3:
  1376.       exit(0);
  1377.       break;
  1378.    }
  1379. }
  1380.  
  1381. int
  1382. main(int argc, char **argv)
  1383. {
  1384.   long i;
  1385.  
  1386.   glutInit(&argc, argv);
  1387.   for (i = 1; i < argc; i++) {
  1388.     if (argv[i][0] == '-') {
  1389.       switch (argv[i][1]) {
  1390.       case 's':
  1391.         doubleBuffer = 0;
  1392.         break;
  1393.       default:
  1394.         Usage();
  1395.       }
  1396.     } else {
  1397.       Usage();
  1398.     }
  1399.   }
  1400.  
  1401.   glutInitWindowSize(W, H);
  1402.   if (doubleBuffer) {
  1403.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
  1404.   } else {
  1405.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE | GLUT_MULTISAMPLE);
  1406.   }
  1407.  
  1408.   glutCreateWindow("glpuzzle");
  1409.  
  1410.   init();
  1411.  
  1412.   glGetIntegerv(GL_VIEWPORT, viewport);
  1413.  
  1414.   printf("\n");
  1415.   printf("r   Reset puzzle\n");
  1416.   printf("s   Solve puzzle (may take a few seconds to compute)\n");
  1417.   printf("d   Destroy a piece - makes the puzzle easier\n");
  1418.   printf("b   Toggles the depth buffer on and off\n");
  1419.   printf("\n");
  1420.   printf("Left mouse moves pieces\n");
  1421.   printf("Middle mouse spins the puzzle\n");
  1422.   printf("Right mouse has menu\n");
  1423.  
  1424.   glutReshapeFunc(Reshape);
  1425.   glutDisplayFunc(redraw);
  1426.   glutKeyboardFunc(keyboard);
  1427.   glutMotionFunc(motion);
  1428.   glutMouseFunc(mouse);
  1429.   glutVisibilityFunc(visibility);
  1430.   glutCreateMenu(menu);
  1431.   glutAddMenuEntry("Solve", 1);
  1432.   glutAddMenuEntry("Reset", 2);
  1433.   glutAddMenuEntry("Quit", 3);
  1434.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  1435.   glutMainLoop();
  1436.   return 0;             /* ANSI C requires main to return int. */
  1437. }
  1438.